home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Diamond Collection
/
The Diamond Collection (Software Vault)(Digital Impact).ISO
/
cdr40
/
radserv.zip
/
TTYORIG.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-11-14
|
15KB
|
530 lines
/* %W% %E% %U% */
/*
* Sample Windows-NT TTY program. Runs as an NT Console Application
* and passes keyboard data to TTY and writes TTY chars to console.
* S.N. 11/2/94.
* Compile with Microsoft WIN32 compiler:
* cl -O1 -Os -DWIN32 tty.c -link -defaultlib:user32,gdi32,advapi32
*/
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
/*
* Flags
*/
#define TTY_RTSCTS 0x1 /* RTS/CTS Handshake */
#define TTY_DSRDTR 0x2 /* DSR/DTR Handshake */
#define TTY_XONXOFF 0x4 /* XON-XOFF Handshake by COM port driver */
typedef struct tag_ttyinfo {
int t_portno;
int t_baudrate;
char t_databits;
char t_parity;
char t_stopbits;
int t_flags;
HANDLE t_ttyh;
HANDLE t_WrEvent;
HANDLE t_RdEvent;
OVERLAPPED t_WrOverlap;
OVERLAPPED t_RdOverlap;
} tty_t;
struct ports {
char *str;
int code;
} Ports[] = {
"COM1", 1, "COM2", 2, "COM3", 3, "COM4", 4, /* etc. etc. etc. */ 0 ,0
};
struct bauds {
char *str;
int code;
} Bauds[] = {
"300", CBR_300, "600", CBR_600, "1200", CBR_1200,
"2400", CBR_2400, "4800", CBR_4800, "9600", CBR_9600,
"14400", CBR_14400, "19200", CBR_19200, 0, 0
};
struct stopbits {
char *str;
int code;
} Stopbits[] = {
"1", ONESTOPBIT, "1.5", ONE5STOPBITS, "2", TWOSTOPBITS, 0, 0
};
struct dbits {
char *str;
int code;
} DataBits[] = {
"5", 5, "6", 6, "7", 7, "8", 8, 0, 0
};
struct parity {
char *str;
int code;
} Parity[] = {
"None", NOPARITY , "Odd", ODDPARITY, "Even", EVENPARITY,
"AlwaysMark", MARKPARITY, "AlwaysSpace", SPACEPARITY, 0, 0
};
BOOL
OpenLine ( tty_t *tp )
{
char portname[24];
BOOL result;
COMMTIMEOUTS CommTimeOuts ;
extern BOOL TTYSetup(tty_t *);
sprintf(portname, "\\\\.\\COM%d", tp->t_portno) ;
tp->t_ttyh = CreateFile( portname, GENERIC_READ | GENERIC_WRITE,
0 /* Exclusive Access */,
NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_OVERLAPPED, NULL);
if (tp->t_ttyh == INVALID_HANDLE_VALUE) {
printf("Cannot open COM%d - error %d\n", tp->t_portno, GetLastError());
return FALSE;
}
CommTimeOuts.ReadIntervalTimeout = 0xffffffff ; /* Indefinite */
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 0xffffffff; /* indefinite */
SetCommTimeouts(tp->t_ttyh, &CommTimeOuts);
result = TTYSetup(tp) ;
if (!result) {
CloseHandle(tp->t_ttyh) ;
return FALSE;
}
SetCommMask(tp->t_ttyh, EV_RING | EV_RXCHAR | EV_DSR | EV_RLSD | EV_BREAK) ;
SetupComm(tp->t_ttyh, 4096, 4096) ;
if ((tp->t_RdEvent = CreateEvent(NULL,TRUE,FALSE,NULL)) == INVALID_HANDLE_VALUE) {
CloseHandle(tp->t_ttyh);
return FALSE;
}
memset (&tp->t_RdOverlap, 0, sizeof(OVERLAPPED));
tp->t_RdOverlap.hEvent = tp->t_RdEvent;
if ((tp->t_WrEvent = CreateEvent(NULL,TRUE,FALSE,NULL)) == INVALID_HANDLE_VALUE) {
CloseHandle(tp->t_ttyh);
return FALSE;
}
memset (&tp->t_WrOverlap, 0, sizeof(OVERLAPPED));
tp->t_WrOverlap.hEvent = tp->t_WrEvent;
/*
* If no hardware handshaking desired, raise DTR and RTS
*/
if (!(tp->t_flags & TTY_DSRDTR))
EscapeCommFunction( tp->t_ttyh, SETDTR);
Sleep(100);
if (!(tp->t_flags & TTY_RTSCTS))
EscapeCommFunction( tp->t_ttyh, SETRTS);
return TRUE;
}
static BOOL
TTYSetup ( tty_t *tp )
{
DCB dcb ;
dcb.DCBlength = sizeof(DCB);
GetCommState(tp->t_ttyh, &dcb) ;
dcb.BaudRate = tp->t_baudrate ;
dcb.ByteSize = tp->t_databits ;
dcb.Parity = tp->t_parity ;
dcb.StopBits = tp->t_stopbits ;
if (dcb.fOutxDsrFlow = ((tp->t_flags & TTY_DSRDTR) != 0))
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE ;
else
dcb.fDtrControl = DTR_CONTROL_ENABLE ;
dcb.fDsrSensitivity = 0;
if (dcb.fOutxCtsFlow = ((tp->t_flags & TTY_RTSCTS) != 0))
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE ;
else
dcb.fRtsControl = RTS_CONTROL_ENABLE ;
dcb.fInX = dcb.fOutX = (BYTE) ((tp->t_flags & TTY_XONXOFF) != 0);
dcb.fTXContinueOnXoff = TRUE;
dcb.fNull = TRUE;
dcb.fAbortOnError = FALSE;
dcb.XonChar = (char )17; /* ASCII XON */
dcb.XoffChar = (char )19; /* ASCII XOFF */
dcb.XonLim = 100;
dcb.XoffLim = 100;
dcb.fBinary = TRUE ;
dcb.fParity = (tp->t_parity != NOPARITY);
return SetCommState( tp->t_ttyh, &dcb ) ;
}
static BOOL
CloseLine(tty_t *tp)
{
BOOL status;
/* Stop receiving event notifications */
SetCommMask( tp->t_ttyh, 0);
/* Drop RTS */
EscapeCommFunction( tp->t_ttyh, CLRRTS);
Sleep(100);
/* Drop DTR */
EscapeCommFunction( tp->t_ttyh, CLRDTR);
Sleep(100);
/* Purge all data in all buffers */
PurgeComm( tp->t_ttyh, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR );
/* Release resources */
if (status = CloseHandle(tp->t_ttyh)) {
tp->t_ttyh = NULL;
CloseHandle(tp->t_RdEvent);
DeleteObject(tp->t_RdEvent);
CloseHandle(tp->t_WrEvent);
DeleteObject(tp->t_WrEvent);
}
return status;
}
/*
* Read up to max nMaxLength chars into lpszBlock.
Returns: 0: Nothing available (nothing received)
>0: No. of chars received (and put in lpszBlock)
-1: Error occured. 'error' contains code (either OS error
code or driver-specific code)
*/
static int
ReadCommBuf(tty_t *tp, LPSTR lpszBlock, int nMaxLength, int *error )
{
BOOL status;
COMSTAT ComStat;
DWORD dwErrorFlags, dwLength;
int lerror;
*error = 0;
ClearCommError(tp->t_ttyh, &dwErrorFlags, &ComStat ) ;
if (dwErrorFlags > 0) {
*error = (int) dwErrorFlags;
return -1;
}
dwLength = min((int)nMaxLength, (int)ComStat.cbInQue);
if (dwLength > 0) {
status = ReadFile( tp->t_ttyh, lpszBlock,
dwLength, &dwLength, &tp->t_RdOverlap) ;
if (!status) {
if ((lerror = GetLastError()) == ERROR_IO_PENDING) {
if (WaitForSingleObject( tp->t_RdOverlap.hEvent, 20000)) {
*error = GetLastError();
return -1;
}
else {
GetOverlappedResult( tp->t_ttyh, &tp->t_RdOverlap, &dwLength, FALSE ) ;
tp->t_RdOverlap.Offset += dwLength;
}
}
else {
printf("\n<Line error %08x>\n", lerror);
*error = lerror;
return -1;
}
}
}
return dwLength;
}
/* Write a character to tty port. If this routine is called at more than
human typing speeds, the stuff inside the ifdef should be included in
the compile.
*/
static void
WriteCommByte(tty_t *tp, BYTE bByte)
{
int status, error;
DWORD BytesWritten;
status = WriteFile( tp->t_ttyh, (LPSTR) &bByte, 1,
&BytesWritten, &tp->t_WrOverlap);
if (!status) {
if ((error = GetLastError()) == ERROR_IO_PENDING) {
status = WaitForSingleObject( tp->t_WrOverlap.hEvent, 10000);
if ( status == WAIT_OBJECT_0 ) {
GetOverlappedResult( tp->t_ttyh, &tp->t_WrOverlap, &BytesWritten, FALSE );
tp->t_WrOverlap.Offset += BytesWritten;
}
else {
/* Other Error occured (including a timeout). */ ;
}
}
else {
/* Other I/O error occured. */ ;
}
}
}
/*
* Write an array of characters to tty port */
static void
WriteCommBuf(tty_t *tp, char *bufp, int len)
{
for (; len > 0; len--)
WriteCommByte(tp, *bufp++);
}
/*
* Open tty line. all parameters are specified in strings (i.e.,
"COM2", "9600", etc. No provision to set the hardware or software
handshaking by setting the appropriate flags, etc.
*/
BOOL
TTYOpen(tty_t *tp, char * portp, char *speedp, char *databitsp, char *stopbitsp,
char *parityp)
{
struct ports *pp;
struct bauds *bp;
struct dbits *dbitsp;
struct stopbits *sp;
struct parity *parp;
tp->t_ttyh = NULL;
if (!portp || !speedp || !parityp || !databitsp || !stopbitsp)
return FALSE;
for (pp = Ports; pp->str; pp++)
if (strcmp(pp->str, portp) == 0)
tp->t_portno = pp->code;
for (bp = Bauds; bp->str; bp++)
if (strcmp(bp->str, speedp) == 0)
tp->t_baudrate = bp->code;
for (dbitsp = DataBits; dbitsp->str; dbitsp++)
if (strcmp(dbitsp->str, databitsp) == 0)
tp->t_databits = dbitsp->code;
for (sp = Stopbits; sp->str; sp++)
if (strcmp(sp->str, stopbitsp) == 0)
tp->t_stopbits = sp->code;
for (parp = Parity; parp->str; parp++)
if (strcmp(parp->str, parityp) == 0)
tp->t_parity = parp->code;
return OpenLine(tp);
}
/*
* Default parameters for the port
*/
tty_t tty = { 2, CBR_19200, 8, NOPARITY, ONESTOPBIT, 0,
NULL, NULL, NULL, { 0 }, { 0 }
};
HANDLE hConOutput, thread;
void /* !!! */
main(ac, av)
char *av[];
{
HANDLE hConInput;
DWORD dummy, mode, oldmode;
char c;
int rd;
extern void Reader(tty_t *);
/*
* Change params as needed: Portname, speed, databits, stopbits, parity.
* Note: not all data and stopbit combinations are supported by the
* driver.
*/
if (!TTYOpen(&tty, "COM2", "14400", "8", "1", "None")) {
printf("can't open/set up port COM2");
exit(0);
}
/*
* Set Keyboard input to uncooked mode (no line delimiter, no echo)
*/
hConInput = GetStdHandle(STD_INPUT_HANDLE);
hConOutput = GetStdHandle(STD_OUTPUT_HANDLE);
if (!hConInput || !hConOutput) {
printf("can't get stdin/stdout handle\n");
exit(1);
}
if (GetConsoleMode(hConInput, &oldmode) == FALSE) {
printf("can't get console mode\n");
exit(1);
}
mode = oldmode; /* Keep a copy for later restoration */
mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
if (SetConsoleMode(hConInput, mode) == FALSE) {
printf("can't set console mode\n");
exit(1);
}
/*
* Create auxiliary thread to read the COM port and write to screen
*/
thread = CreateThread ((LPSECURITY_ATTRIBUTES)NULL, (DWORD)0,
(LPTHREAD_START_ROUTINE)Reader, (LPVOID)&tty,
(DWORD)0, (LPDWORD)&dummy);
if (thread == INVALID_HANDLE_VALUE) {
printf("can't create reader thread\n");
exit(1);
}
/*
* Begin main thread. Read keyboard and write to the COM port.
*/
for(;;) {
if (ReadFile(hConInput, &c, 1, &rd, NULL) == FALSE)
break;
if (rd > 0)
WriteCommByte(&tty, c);
if (!thread) { /* Beware of compiler optimizations */
printf("\nOops! Reader went away. Exiting...\n");
break;
}
}
if (thread)
(void) TerminateThread(thread /* bye-bye */, 0);
if (CloseLine(&tty))
printf("Line Closed\n");
else
printf("error closing com port\n");
(void) SetConsoleMode(hConInput, oldmode); /* if we can't set , tuff */
exit(0);
}
static void
Reader(tty_t *tp)
{
int rd, error, nwr, status;
int EventMask;
char buf[256];
printf("\nDumb Terminal Emulator Program\n");
printf("**** IGOR LABS ****\n");
printf("**** Falls Church, VA 22042 ****\n");
printf("\nCOM2 Baudrate:14400 8bits 1Stopbit NoParity\n");
printf("\nHit Control-C To Exit (YOU CAN'T PASS ^C TO REMOTE)\n");
fflush(stdout);
for (;;) {
EventMask = 0;
/* Wait for 10 seconds for something to happen */
#ifdef WEWANTTOBEASCOMPLICATEDASPOSSIBLE
status = WaitCommEvent(tp->t_ttyh, &EventMask, &tp->t_RdOverlap);
if (!status) {
error = GetLastError();
if ((unsigned)error == ERROR_IO_PENDING)
WaitForSingleObject(tp->t_RdEvent, 10000);
else {
printf("\n<Error (%d)>\n", error);
break;
}
}
#else
/*
* Wait indefinitely (barring a ^C) for something to
* happen on the COM port.
*/
(void) WaitCommEvent(tp->t_ttyh, &EventMask, NULL);
#endif
if (EventMask & (EV_DSR| EV_RLSD | EV_BREAK | EV_RING)) {
GetCommModemStatus(tp->t_ttyh, &status);
if (EventMask & EV_DSR)
printf("\n<DSR %sASSERTED>\n", (status & MS_DSR_ON) ? "" : "DE");
if (EventMask & EV_RLSD);
printf("\n<CARRIER DETECT %sASSERTED>\n", (status & MS_RLSD_ON) ? "" : "DE");
if (EventMask & EV_BREAK)
printf("\n<LINE BREAK>\n");
if ((EventMask & EV_RING) && (status & MS_RING_ON))
printf("\n<RRRRING!>\n");
}
/* Now attend to the business of reading the port and echoing */
if (EventMask & EV_RXCHAR) {
do {
rd = ReadCommBuf(tp, buf, sizeof buf, &error);
if (rd > 0)
WriteFile(hConOutput, buf, rd, &nwr, NULL);
} while(rd > 0);
}
}
/*
* If "wrong" level of optimization is used when compiling, the
* main thread may not be able to discover that the value of the
* handle "thread" (below) has changed (i.e., variable aliasing.)
* This can be avoided by resetting the console mode and
* TerminateProcess(). For now, we just go ahead with this method.
*/
thread = NULL; /* Signal main thread we're exiting */
ExitThread(0);
}